﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace nGSO.KnapsackProblem
{
    public class KPSearchSpace : SearchSpace
    {
        private readonly KpConfigElement _kpconfig;
        private int _kpitems;
        private KPFitnessCalulator _fitnessCalc;
        private static Random _rand = new Random();
        
        
        public KPSearchSpace(GsoConfig config, KpConfigElement kpConfig) : base(config)
        {
            config.Dims = kpConfig.Dims;

            _kpconfig = kpConfig;
            _kpitems = kpConfig.Costs.Count();
            _fitnessCalc = new KPFitnessCalulator(kpConfig);
            
        }

        protected override void SetInitialAgentLocation(Random rand, Agent agent)
        {
            agent.Loc = new double[_kpconfig.Dims]; // items quantity == number of dimensions

            for (int i = 0; i < _kpconfig.Dims; i++)
            {
                double x = rand.NextDouble();
                agent.Loc[i] = (x > 0.5) ? 1 : 0; // todo location should be represented by int
            }
        }

        public override void MoveAgent(Agent agent, Agent agentToMoveToward)
        {
            // a moves to b
            double[] aLoc = agent.Loc;
            double[] bLoc = agentToMoveToward.Loc;

            // 'a' new location
            double[] newLoc = new double[_config.Dims];

            double[] diffVecor = new double[_config.Dims];  
            for (int i = 0; i < _config.Dims; i++)
            {
                diffVecor[i] = (aLoc[i] != bLoc[i]) ? 1 : 0;
            }

            int diffCounter = diffVecor.Count(s => s == 1);
            int minRandChangs = (int)(_config.StepSize * diffCounter * _config.Dims);

            if (diffCounter < minRandChangs)
                minRandChangs = _rand.Next(0, diffCounter);

            int propotion = _rand.Next(minRandChangs, diffCounter); //(int)(diffCounter / _config.Dims / _config.StepSize);
            
            List<int> diffIndexes = new List<int>();
            for (int i = 0; i < diffVecor.Length; i++)
			{
			    if (diffVecor[i] == 1)
                {
                    diffIndexes.Add(i);
                }
			}

            for (int i = 0; i < _config.Dims; i++)
            {
                newLoc[i] = aLoc[i];
            }

            
            for (int i = 0; i < propotion; i++)
            {
                int tmpIndx = _rand.Next(0, diffIndexes.Count - 1);
                int indexToChange = diffIndexes[tmpIndx];

                newLoc[indexToChange] = (aLoc[indexToChange] == 1) ? 0 : 1;

                diffIndexes.RemoveAt(tmpIndx);
            }
            
            agent.NextLoc = newLoc;
        }
    }
}
